#pragma once

#include "../LibBuildNG/Module.hpp"

namespace BuildNG
{
  class InputFilesSet;

  class CLangReference;
  class CCompilerBackend;
  
  class CLangModule : public Module
  {
  public:
    CLangModule();

    virtual void load_from_xml(const Xml::Element &xml);
    virtual void save_to_xml(Xml::Element &xml) const;
    
    enum OutputType
    {
      OutputType_Executable,
      OutputType_Library,
      OutputType_SharedLibrary,
    };

    virtual bool build(BuildContext &context,Glib::RefPtr<ErrorListener> error_listener);

  protected:
    virtual bool supports_cpp() const = 0;

  private:
    Glib::RefPtr<InputFilesSet>       input_files;
    OutputType                        output_type;
    std::vector<Glib::RefPtr<CLangReference> >  references;

    struct CLangBuildContext
    {
      std::vector<Glib::ustring> object_files;
    };
    
    void read_references(const Xml::Element &xml);

    bool build_source_files(
      BuildContext&                 context,
      CLangBuildContext&            clang_context,
      Glib::RefPtr<ErrorListener>   error_listener);

    bool build_object_files(
      BuildContext&                 context,
      CLangBuildContext&            clang_context,
      Glib::RefPtr<ErrorListener>   error_listener);

    static Glib::RefPtr<CCompilerBackend> get_backend();
  };
  
  class CLangReference : public Object
  {
  public:  
    enum ReferenceType
    {
      ReferenceType_Package,
      ReferenceType_Module,
    };
    ReferenceType     reference_type;    
    Glib::ustring     name;
  };

  class PlainCModule : public CLangModule
  {
  public:
    static void init();
    static void shutdown();

  protected:
    virtual bool supports_cpp() const;
  };

  class CppModule : public CLangModule
  {
  public:
    static void init();
    static void shutdown();

  protected:
    virtual bool supports_cpp() const;
  };

  enum CLangSourceFileType
  {
    CLangSourceFileType_Unknown,
    CLangSourceFileType_CSource,
    CLangSourceFileType_CppSource,
    CLangSourceFileType_Header,
  };
  
  CLangSourceFileType clang_source_file_type_by_ext(const Glib::ustring &file_name);
}

